// Copyright Gary Evans 2006-2007.

using System;
using System.Collections.Generic;
using System.Text;

namespace Taumuon.Jabuka.Physics.Test
{
    /// <summary>
    /// Mock object to facilitate testing.
    /// </summary>
    public class MockEulerRigidBody : IEulerRigidBody
	{
		#region Object Lifetime

		/// <summary>
		/// Default constructor.
		/// </summary>
		public MockEulerRigidBody()
		{
			this.location = new Vector();
			this.velocity = new Vector();
			this.acceleration = new Vector();
			this.mass = double.NaN;
		}

		/// <summary>
		/// Constructor
		/// </summary>
		public MockEulerRigidBody(Vector location, Vector velocity, Vector acceleration, double mass)
		{
			this.location = location;
			this.velocity = velocity;
			this.acceleration = acceleration;
			this.mass = mass;
		}

		#endregion Object Lifetime

		#region IEulerRigidBody Members

        /// <summary>
        /// Implementation of the Location property.
        /// </summary>
		public Vector Location
        {
            get { return this.location; }
        }

        /// <summary>
        /// Implementation of the Velocity property.
        /// </summary>
        public Vector Velocity
        {
            get { return this.velocity; }
        }

        /// <summary>
        /// Implementation of the Acceleration property.
        /// </summary>
		public Vector Acceleration
		{
			get { return this.acceleration; }
		}

        /// <summary>
        /// Implementation of the Mass property.
        /// </summary>
        public double Mass
        {
			get { return this.mass; }
        }

        /// <summary>
        /// Implementation of the Update method.
        /// </summary>
        public void Update(double deltaTime)
        {
			this.updateTimes.Add(deltaTime);
        }

		/// <summary>
		/// Retrieves the current force being applied to the object.
		/// </summary>
		public Vector AppliedForce
		{
			get	{ return null; }
		}

        /// <summary>
        /// Implementation of the ApplyForce method.
        /// </summary>
        public void ApplyForce(Vector force)
        {
        }

        /// <summary>
        /// Assigns the property on this instance from the passed in rigid body.
        /// </summary>
        /// <param name="rhs"></param>
		public void AssignFromEulerRigidBody(IEulerRigidBody rhs)
		{
			#region Code Copied from EulerRigidBody as CollisionManager tested through interface
			this.location.SetValues(rhs.Location.X, rhs.Location.Y, rhs.Location.Z);
			this.velocity.SetValues(rhs.Velocity.X, rhs.Velocity.Y, rhs.Velocity.Z);
			if (this.force == null)
			{
				if (rhs.AppliedForce != null)
				{
					this.force = rhs.AppliedForce.Clone() as Vector;
				}
			}
			else
			{
				if (rhs.AppliedForce == null)
				{
					this.force = null;
				}
				else
				{
					this.force.SetValues(rhs.AppliedForce.X, rhs.AppliedForce.Y, rhs.AppliedForce.Z);
				}
			}

			this.mass = rhs.Mass;
			#endregion Code Copied from EulerRigidBody as CollisionManager tested through interface

			assignFromCalled = true;
		}

        #endregion

		#region Test Support

		/// <summary>
		/// This is set to true once the Update() method is called.
		/// </summary>
		public bool UpdateCalled
		{
			get
			{
				return this.updateTimes.Count > 0;
			}
		}

        /// <summary>
        /// Returns the list of times that Update was called with on this instance.
        /// </summary>
        public List<double> UpdateTimes
        {
            get
            {
                return this.updateTimes;
            }
        }

		/// <summary>
		/// This is set to true once the Clone() method is called.
		/// </summary>
		public bool CloneCalled
		{
			get
			{
				return this.cloneCalled;
			}
		}

		/// <summary>
		/// True once AssignFromEulerRigidBody is called.
		/// </summary>
		public bool AssignFromCalled
		{
			get
			{
				return this.assignFromCalled;
			}
		}

        /// <summary>
        /// Implementation of the CloneFactory property.
        /// </summary>
        public IMockClonesFactory<MockEulerRigidBody> CloneFactory
        {
            get
            {
                return this.mockEulerRigidBodyClonesFactory;
            }
            set
            {
                this.mockEulerRigidBodyClonesFactory = value;
            }
        }

		#endregion Test Support

        #region ICloneable Members

        /// <summary>
        /// Performs a deep copy.
        /// </summary>
        /// <returns>A copy of the object.</returns>
        public object Clone()
        {
			cloneCalled = true;
            if (mockEulerRigidBodyClonesFactory != null)
            {
                return this.mockEulerRigidBodyClonesFactory.GetNextClone();
            }
            else
            {
                return null;
            }
        }

        #endregion ICloneable Members

		#region Private Member Variables

		private List<double> updateTimes = new List<double>();
		private bool cloneCalled = false;
		private bool assignFromCalled = false;
        private IMockClonesFactory<MockEulerRigidBody> mockEulerRigidBodyClonesFactory;
		private Vector location = null;
		private Vector velocity = null;
		private Vector acceleration = null;
		private Vector force = null;
		private double mass = 0.0;

		#endregion Private Member Variables
	}
}
